package com.jt808.decode.utils;

import com.jt808.decode.constant.Jt808Constant;
import com.jt808.decode.model.Jt808Message;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufAllocator;
import io.netty.buffer.ByteBufUtil;
import io.netty.util.ReferenceCountUtil;
import lombok.extern.slf4j.Slf4j;

/**
 * JT808指令编码
 * @author HyoJung
 * @date 20230303
 */
@Slf4j
public class Jt808ProtocolEncoder {
    /**
     * 指令组装
     * @param msg
     * @return
     */
    public static String encode(Jt808Message msg){
        ByteBuf msgBody = msg.getMsgBody();
        int msgBodyLen = msgBody == null ? 0 : msgBody.readableBytes();
        int versionFlag=msg.getVersionFlag();
        //the length of remove the tip and tail
        int contentLen = versionFlag == 1 ? Jt808Constant.JT2019_MSG_BASE_LENGTH + msgBodyLen - 2 : Jt808Constant.MSG_BASE_LENGTH + msgBodyLen - 2;
        if (msg.isMultiPacket()) {
            contentLen = contentLen + 4;
        }
        String replyMsg="";
        ByteBuf bodyBuf = ByteBufAllocator.DEFAULT.heapBuffer(contentLen);
        try {
            //message id
            bodyBuf.writeShort(msg.getMsgId());
            //The length of the message body in the message body property
            int msgBodyAttr = msgBodyLen | (msg.getEncryptType() << 10);
            //The subcontract identity in the message body property
            if (msg.isMultiPacket()) {
                msgBodyAttr = msgBodyAttr | 0b00100000_00000000;
            }

            //The Jt808-2019 version adds the version identifier and protocol version number
            if (versionFlag == 1) {
                //Version identification
                msgBodyAttr = msgBodyAttr | 0b01000000_00000000;
                //message body property
                bodyBuf.writeShort(msgBodyAttr);
                //Protocol version Number
                bodyBuf.writeByte(msg.getProtocolVersion());
            } else {
                //message body properties
                bodyBuf.writeShort(msgBodyAttr);
            }

            //terminal number
            bodyBuf.writeBytes(msg.getPhoneNumberArr());
            //Message serial number
            bodyBuf.writeShort(msg.getMsgFlowId());
            //Package item of message (subcontracting needs to add the total number of message packets and packet number)
            if (msg.isMultiPacket()) {
                bodyBuf.writeShort(msg.getPacketTotalCount());
                bodyBuf.writeShort(msg.getPacketOrder());
            }
            //message body
            if (msgBodyLen > 0) {
                bodyBuf.writeBytes(msgBody);
            }
            //check code
            int checkCode = CommonUtil.xor(bodyBuf);
            bodyBuf.writeByte(checkCode);
            ByteBuf out = ByteBufAllocator.DEFAULT.heapBuffer(contentLen+2);
            //message header
            out.writeByte(Jt808Constant.MSG_HEAD_TAIL_FLAG);
            //The read index is reset to the starting position
            bodyBuf.readerIndex(0);
            //escape
            Jt808PacketUtil.escape(out, bodyBuf);
            //message tail
            out.writeByte(Jt808Constant.MSG_HEAD_TAIL_FLAG);
            byte[] msgArr=new byte[out.readableBytes()];
            out.readBytes(msgArr);
            replyMsg = ByteBufUtil.hexDump(msgArr);
        } catch (Exception e) {
            log.error("message encoding exception,message:{}", msg, e);
        } finally {
            //release message body
            if (msgBody != null) {
                ReferenceCountUtil.release(msgBody);
            }
            //release bodyBuf
            ReferenceCountUtil.release(bodyBuf);
        }
        return replyMsg;
    }
}
